package com.leyou.search.service;

import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.SpecParam;
import com.leyou.search.client.BrandClient;
import com.leyou.search.client.CategoryClient;
import com.leyou.search.client.SpecificationClient;
import com.leyou.search.pojo.Goods;
import com.leyou.search.pojo.SearchRequest;
import com.leyou.search.pojo.SearchResult;
import com.leyou.search.repository.GoodsRepository;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.Operator;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.terms.LongTerms;
import org.elasticsearch.search.aggregations.bucket.terms.StringTerms;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 项目: leyou
 *
 * @author 岩冰
 * @version 2018/10/11 12:13
 */
@Service
public class SearchService {
    @Autowired
    private GoodsRepository goodsRepository;

    @Autowired
    private CategoryClient categoryClient;
    @Autowired
    private BrandClient brandClient;
    @Autowired
    private SpecificationClient specificationClient;

    public SearchResult search(SearchRequest searchRequest) {

        //判断key非空
        if (searchRequest.getKey() == null) {
            return null;
        }
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();

       QueryBuilder query= buildBasicQueryWithFilter(searchRequest);
        //将布尔条件传下去
        searchQueryBuilder.withQuery(query);
        //添加聚合条件和排序条件
        pageSourtQuery(searchRequest, searchQueryBuilder);
        // 1.3、聚合
        String brandAggName = "brand"; // 品牌聚合名称
        searchQueryBuilder.addAggregation(AggregationBuilders.terms(brandAggName).field("brandId"));
        //分类聚合查询
        String categoryAggName = "category"; // 商品分类聚合名称
        searchQueryBuilder.addAggregation(AggregationBuilders.terms(categoryAggName).field("cid3"));

        AggregatedPage<Goods> page = (AggregatedPage<Goods>) goodsRepository.search(searchQueryBuilder.build());
        LongTerms categoryAgg = (LongTerms) page.getAggregation(categoryAggName);


        List<Category> categories = getCategorys(categoryAgg);
        LongTerms brandAggs = (LongTerms) page.getAggregation(brandAggName);
       List<Brand>brands= this.getBrands(brandAggs);
        List<Map<String, Object>> specs = null;
        if (categories != null && categories.size() == 1) {
            //需要聚合参数
            specs=this.getSpecs(categories.get(0).getId(),query);
        }
        return new SearchResult(page.getTotalElements(), (long) page.getTotalPages(), page.getContent(), categories, brands, specs);
    }

    private void pageSourtQuery(SearchRequest searchRequest, NativeSearchQueryBuilder searchQueryBuilder) {
        searchQueryBuilder.withSourceFilter(new FetchSourceFilter(new String[]{"subTitle", "skus", "id"}, null));
        //正常查询
        searchQueryBuilder.withPageable(PageRequest.of(searchRequest.getPage()-1, searchRequest.getSize()));
        if (StringUtils.isNotBlank(searchRequest.getSortBy())) {
            searchQueryBuilder.withSort(SortBuilders.fieldSort(searchRequest.getSortBy()).
                    order(searchRequest.getDescending() ? SortOrder.DESC : SortOrder.ASC));
        }
    }

    /**
     * 聚合要在过滤的基础上
     * @param id
     * @param queryBuilder
     * @return
     */
    private List<Map<String, Object>> getSpecs(Long id, QueryBuilder queryBuilder) {
            //先根据cateGery的id 查询出所有的categoryParam的key
        List<SpecParam> specParams = specificationClient.querySpecParams(null, id, true, null);
        NativeSearchQueryBuilder searchQueryBuilder = new NativeSearchQueryBuilder();
        searchQueryBuilder.withQuery(queryBuilder);
        //拿到所有的字符串,添加映射
          specParams.stream().map(SpecParam::getName).forEach(name->
            searchQueryBuilder.addAggregation(AggregationBuilders.terms(name).field("specs."+name+".keyword")));
        AggregatedPage<Goods> goodsPage = (AggregatedPage<Goods>) this.goodsRepository.search(searchQueryBuilder.build());
        Map<String, Aggregation> aggs = goodsPage.getAggregations().asMap();
        List<Map<String, Object>> specs = new ArrayList<>();
        specParams.forEach(param->{
        try {
            Map<String, Object> spec = new HashMap<>();
            String key = param.getName();
            spec.put("k", key);
            StringTerms terms = (StringTerms) aggs.get(key);
            spec.put("options", terms.getBuckets().stream().map(StringTerms.Bucket::getKeyAsString));
            specs.add(spec);
        } catch (Exception e) {
//            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        });
        return specs;
    }
    private List<Brand> getBrands(LongTerms brandAggs) {
        try {
            List<Long> brandIds = brandAggs.getBuckets().stream().map(bucket ->
                    bucket.getKeyAsNumber().longValue()).collect(Collectors.toList());
            List<Brand> brands = brandClient.queryBrandByIds(brandIds);
            return brands;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.print("查询异常");
        }
        return null;
    }

    private List<Category> getCategorys(LongTerms categoryAgg) {
        try {
            //从结果中解析出cids
            List<Long> cids = categoryAgg.getBuckets().
                    stream().map(bucket -> bucket.getKeyAsNumber().longValue()).collect(Collectors.toList());
            List<String> categoryNames = categoryClient.queryNamesByIds(cids);
            ArrayList<Category> categories = new ArrayList<>();
            for (int i = 0; i < categoryNames.size(); i++) {
                Category category = new Category().setId(cids.get(i)).setName(categoryNames.get(i));
                categories.add(category);
            }
            return categories;
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("查询服务器异常");
            return null;
        }
    }

    private QueryBuilder buildBasicQueryWithFilter(SearchRequest searchRequest) {

         BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
      //添加一个and条件
        queryBuilder.must(QueryBuilders.matchQuery("all",
                searchRequest.getKey()).operator(Operator.AND));
        //拿到顾虑条件
        Map<String, String> filter = searchRequest.getFilter();
        //分别添加条件,再查询
        BoolQueryBuilder filterQuery = QueryBuilders.boolQuery();
        filter.forEach((key, value) -> {
            // 商品分类和品牌已经聚合
            if (key!="cid3" &&key!="brandId") {
                key = "specs." + key + ".keyword";
                filterQuery.must(QueryBuilders.termQuery(key, value));
            }
        });
        //添加过滤
        queryBuilder.filter(filterQuery);

        return queryBuilder;
    }
}
